<template>
  <div class="image-upload">
    <el-upload
      ref="uploadRef"
      :action="action"
      :before-upload="beforeUpload"
      :on-success="handleSuccess"
      :on-error="handleError"
      :on-remove="handleRemove"
      :file-list="fileList"
      :limit="limit"
      :accept="accept"
      :auto-upload="autoUpload"
      :show-file-list="showFileList"
      :drag="drag"
      :multiple="multiple"
      :disabled="disabled"
      class="upload-component"
    >
      <template v-if="drag">
        <div class="upload-dragger">
          <el-icon class="upload-icon"><UploadFilled /></el-icon>
          <div class="upload-text">
            <p>将文件拖到此处，或<em>点击上传</em></p>
            <p class="upload-tip">{{ uploadTip }}</p>
          </div>
        </div>
      </template>
      
      <template v-else>
        <el-button :disabled="disabled" :loading="uploading">
          <el-icon><Upload /></el-icon>
          {{ buttonText }}
        </el-button>
      </template>
    </el-upload>
    
    <!-- 图片预览 -->
    <div v-if="previewImage && showPreview" class="image-preview">
      <div class="preview-container">
        <img :src="previewImage" alt="预览图片" />
        <div class="preview-actions">
          <el-button size="small" @click="removePreview">
            <el-icon><Delete /></el-icon>
            删除
          </el-button>
        </div>
      </div>
    </div>
    
    <!-- Base64预览 -->
    <div v-if="base64Data && showBase64Preview" class="base64-preview">
      <div class="preview-container">
        <img :src="`data:image/jpeg;base64,${base64Data}`" alt="Base64图片" />
        <div class="preview-actions">
          <el-button size="small" @click="clearBase64">
            <el-icon><Delete /></el-icon>
            清除
          </el-button>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'
import { ElMessage } from 'element-plus'
import { Upload, UploadFilled, Delete } from '@element-plus/icons-vue'
import { fileToBase64, checkFileType, checkFileSize, formatFileSize } from '@/utils/auth'

// Props
const props = defineProps({
  // 上传地址
  action: {
    type: String,
    default: '#'
  },
  // 文件列表
  modelValue: {
    type: Array,
    default: () => []
  },
  // 最大上传数量
  limit: {
    type: Number,
    default: 1
  },
  // 接受的文件类型
  accept: {
    type: String,
    default: 'image/*'
  },
  // 允许的文件类型
  allowedTypes: {
    type: Array,
    default: () => ['jpg', 'jpeg', 'png', 'bmp', 'gif']
  },
  // 最大文件大小（字节）
  maxSize: {
    type: Number,
    default: 10 * 1024 * 1024 // 10MB
  },
  // 是否自动上传
  autoUpload: {
    type: Boolean,
    default: false
  },
  // 是否显示文件列表
  showFileList: {
    type: Boolean,
    default: true
  },
  // 是否支持拖拽上传
  drag: {
    type: Boolean,
    default: false
  },
  // 是否支持多选
  multiple: {
    type: Boolean,
    default: false
  },
  // 是否禁用
  disabled: {
    type: Boolean,
    default: false
  },
  // 按钮文字
  buttonText: {
    type: String,
    default: '选择文件'
  },
  // 是否显示预览
  showPreview: {
    type: Boolean,
    default: true
  },
  // 是否显示Base64预览
  showBase64Preview: {
    type: Boolean,
    default: false
  },
  // 是否转换为Base64
  convertToBase64: {
    type: Boolean,
    default: false
  }
})

// Emits
const emit = defineEmits(['update:modelValue', 'success', 'error', 'remove', 'base64'])

// Refs
const uploadRef = ref(null)
const uploading = ref(false)
const previewImage = ref('')
const base64Data = ref('')

// Computed
const fileList = computed({
  get: () => props.modelValue,
  set: (value) => emit('update:modelValue', value)
})

const uploadTip = computed(() => {
  const types = props.allowedTypes.join('、')
  const size = formatFileSize(props.maxSize)
  return `支持 ${types} 格式，文件大小不超过 ${size}`
})

// 上传前检查
const beforeUpload = async (file) => {
  // 检查文件类型
  if (!checkFileType(file, props.allowedTypes)) {
    ElMessage.error(`文件类型不支持，请选择 ${props.allowedTypes.join('、')} 格式的文件`)
    return false
  }
  
  // 检查文件大小
  if (!checkFileSize(file, props.maxSize)) {
    ElMessage.error(`文件大小不能超过 ${formatFileSize(props.maxSize)}`)
    return false
  }
  
  uploading.value = true
  
  // 如果需要转换为Base64
  if (props.convertToBase64) {
    try {
      const base64 = await fileToBase64(file)
      base64Data.value = base64
      emit('base64', base64)
      
      // 创建预览URL
      previewImage.value = URL.createObjectURL(file)
      
      uploading.value = false
      return false // 阻止自动上传
    } catch (error) {
      ElMessage.error('文件处理失败')
      uploading.value = false
      return false
    }
  }
  
  return true
}

// 上传成功
const handleSuccess = (response, file, fileList) => {
  uploading.value = false
  ElMessage.success('上传成功')
  emit('success', response, file, fileList)
}

// 上传失败
const handleError = (error, file, fileList) => {
  uploading.value = false
  ElMessage.error('上传失败')
  emit('error', error, file, fileList)
}

// 移除文件
const handleRemove = (file, fileList) => {
  emit('remove', file, fileList)
}

// 移除预览
const removePreview = () => {
  previewImage.value = ''
  if (uploadRef.value) {
    uploadRef.value.clearFiles()
  }
}

// 清除Base64
const clearBase64 = () => {
  base64Data.value = ''
  previewImage.value = ''
  emit('base64', '')
}

// 手动上传
const submit = () => {
  if (uploadRef.value) {
    uploadRef.value.submit()
  }
}

// 清空文件列表
const clearFiles = () => {
  if (uploadRef.value) {
    uploadRef.value.clearFiles()
  }
  previewImage.value = ''
  base64Data.value = ''
}

// 暴露方法
defineExpose({
  submit,
  clearFiles
})
</script>

<style scoped>
.image-upload {
  width: 100%;
}

.upload-dragger {
  padding: 40px;
  text-align: center;
  border: 2px dashed #d9d9d9;
  border-radius: 6px;
  cursor: pointer;
  transition: border-color 0.3s;
}

.upload-dragger:hover {
  border-color: #409eff;
}

.upload-icon {
  font-size: 48px;
  color: #c0c4cc;
  margin-bottom: 16px;
}

.upload-text p {
  margin: 0;
  color: #606266;
}

.upload-text em {
  color: #409eff;
  font-style: normal;
}

.upload-tip {
  font-size: 12px;
  color: #909399;
  margin-top: 8px;
}

.image-preview,
.base64-preview {
  margin-top: 16px;
}

.preview-container {
  position: relative;
  display: inline-block;
  border: 1px solid #dcdfe6;
  border-radius: 6px;
  overflow: hidden;
}

.preview-container img {
  max-width: 200px;
  max-height: 200px;
  display: block;
}

.preview-actions {
  position: absolute;
  top: 8px;
  right: 8px;
  opacity: 0;
  transition: opacity 0.3s;
}

.preview-container:hover .preview-actions {
  opacity: 1;
}
</style>
